﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace A2DFramework.RuleEngine
{
    class Parser
    {
        internal static Declare ParseDeclare(string ruleContent)
        {
            Declare declare = new Declare();

            if (ruleContent == null)
                return declare;
            if (ruleContent.Trim().Length <= 0)
                return declare;

            string[] lines = ruleContent.Split("\r\n".ToCharArray());
            if (lines == null)
                return declare;
            if (lines.Length == 0)
                return declare;

            List<string> filteredLines = FilterEmptyRow(lines);

            declare = null;
            int rowIndex = -1;
            for (int i = 0; i < filteredLines.Count; i++)
            {
                string line = filteredLines[i];

                if (line.Trim().Length >= 7 && line.Substring(0, 7) == "declare")
                {
                    rowIndex = i;

                    declare = new Declare();
                }
                else if (line.Trim().Length >= 11 && line.Substring(0, 11) == "end declare")
                {
                    if (declare == null)
                        throw new Exception("Declare Parse error");

                    if (declare != null)
                    {
                        declare.InnerRawContent = GetInnerRawContent(filteredLines, rowIndex + 1, i - 1);

                        rowIndex = -1;
                    }
                }
            }
            if (declare == null)
            {
                declare = new Declare();
                declare.InnerRawContent = "";
            }


            string[] declares = declare.InnerRawContent.Split("\r\n".ToCharArray());
            List<string> declarelist = FilterEmptyRow(declares);

            declare.Declares = declarelist;

            return declare;
        }

        
        internal static List<Rule> ParseRules(string ruleContent)
        {
            List<Rule> rules = new List<Rule>();

            if (ruleContent == null)
                return rules;
            if (ruleContent.Trim().Length <= 0)
                return rules;

            string[] lines = ruleContent.Split("\r\n".ToCharArray());
            if (lines == null)
                return rules;
            if (lines.Length == 0)
                return rules;

            List<string> filteredLines = FilterEmptyRow(lines);

            Rule rule = null;
            int ruleIndex = -1;
            for (int i = 0; i < filteredLines.Count; i++)
            {
                string line = filteredLines[i];

                if (line.Trim().Length > 4 && line.Substring(0, 4) == "rule")
                {
                    ruleIndex = i;

                    rule = new Rule();
                    rule.Description = line.Substring(5).Trim('"');
                }
                else if (line.Trim().Length >= 8 && line.Substring(0, 8) == "end rule")
                {
                    if(rule==null)
                        throw new Exception("Rule Parse error");

                    if (rule != null)
                    {
                        rule.InnerRawContent = GetInnerRawContent(filteredLines, ruleIndex+1, i-1);
                        rules.Add(rule);

                        ruleIndex = -1;
                    }   
                }
            }

            foreach(Rule r in rules)
            {
                string whenRawContent = GetWhenRawContent(r.InnerRawContent);
                string thenRawContent = GetThenRawContent(r.InnerRawContent);

                string[] whens = whenRawContent.Split("\r\n".ToCharArray());
                List<string> whenlist = FilterEmptyRow(whens);

                string[] thens = thenRawContent.Split("\r\n".ToCharArray());
                List<string> thenlist = FilterEmptyRow(thens);

                r.Whens = whenlist;
                r.Thens = thenlist;
            }

            if (rules.Count == 0)
                throw new Exception("Rule cannot be empty");

            foreach (Rule r in rules)
            {
                if (r.Whens == null || r.Whens.Count == 0)
                    throw new Exception("When cannot be empty");

                if (r.Thens == null || r.Thens.Count == 0)
                    throw new Exception("Then cannot be empty");
            }

            return rules;
        }

        private static List<string> FilterEmptyRow(string[] lines)
        {
            List<string> filteredLines = new List<string>();
            foreach (string line in lines)
                if (line.Trim().Length > 0)
                    filteredLines.Add(line.Trim());
            return filteredLines;
        }
        private static string GetThenRawContent(string contentBlock)
        {
            string[] lines = contentBlock.Split("\r\n".ToCharArray());
            if (lines == null || lines.Length == 0)
                return string.Empty;

            List<string> filteredLines = FilterEmptyRow(lines);

            int beginIndex = -1;
            for (int i = 0; i < filteredLines.Count; i++)
            {
                string line = filteredLines[i];
                if (line.Trim().Length >= 4 && line.Substring(0, 4) == "then")
                {
                    beginIndex = i + 1;
                }
            }
            return GetInnerRawContent(filteredLines, beginIndex, filteredLines.Count - 1);
        }

        private static string GetWhenRawContent(string contentBlock)
        {
            string[] lines = contentBlock.Split("\r\n".ToCharArray());
            if (lines == null || lines.Length == 0)
                return string.Empty;

            List<string> filteredLines = FilterEmptyRow(lines);

            int beginIndex = -1;
            int endIndex = -1;
            for (int i = 0; i < filteredLines.Count; i++)
            {
                string line = filteredLines[i];
                if (line.Trim().Length >= 4 && line.Substring(0, 4) == "when")
                {
                    beginIndex = i+1;
                }
                else if (line.Trim().Length >= 4 && line.Substring(0, 4) == "then")
                {
                    endIndex = i-1;
                    break;
                }
            }
            return GetInnerRawContent(filteredLines, beginIndex, endIndex);
        }

        private static string GetInnerRawContent(string[] lines, int startRowIndex, int endRowIndex)
        {
            return GetInnerRawContent(lines.ToList(), startRowIndex, endRowIndex);
        }
        private static string GetInnerRawContent(List<string> lines, int startRowIndex, int endRowIndex)
        {
            string str = string.Empty;
            int i=startRowIndex;
            while(i<=endRowIndex)
                str += lines[i++]+"\r\n";
            return str;
        }
    }
}
